package com.sanweibook.jhook.common.util;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.util.Assert;

import java.util.List;
import java.util.Map;

/**
 * Created by twg on 17/3/15.
 */
@Slf4j
public final class JhookObjectUtils extends org.apache.commons.lang3.ObjectUtils {

    private static final Map<String, BeanCopier> beanCopierMap = Maps.newHashMap();

    private JhookObjectUtils() {
    }

    /**
     * 对象转字符串
     * <p/>
     * Integer d = new Integer(2);
     * return 2
     *
     * @param object
     * @return
     */
    public static String objectToString(final Object object) {
        return object == null ? "" : String.valueOf(object);
    }

    /**
     * 对象转字符串
     *
     * @param object
     * @param nullString null时，返回nullString的值
     * @return
     */
    public static String objectToString(final Object object, final String nullString) {
        return object == null ? nullString : String.valueOf(object);
    }

    /**
     * 对象转json字符串
     *
     * @param object
     * @return
     */
    public static String objectToJson(final Object object) {
        Assert.notNull(object);
        return JSON.toJSONString(object);
    }

    /**
     * 对象转byte
     *
     * @param object
     * @return
     */
    public static byte[] objectToBytes(final Object object) {
        Assert.notNull(object);
        return JSON.toJSONBytes(object);
    }

    /**
     * json字符串转对象
     *
     * @param json
     * @param tClass
     * @param <T>
     * @return
     */
    public static <T> T jsonToObject(final String json, final Class<T> tClass) {
        Assert.notNull(json);
        Assert.notNull(tClass);
        return JSON.parseObject(json, tClass);
    }

    /**
     * bytes转对象
     *
     * @param bytes
     * @param tClass
     * @param <T>
     * @return
     */
    public static <T> T bytesToObject(final byte[] bytes, final Class<T> tClass) {
        Assert.notNull(bytes);
        Assert.notNull(tClass);
        return JSON.parseObject(bytes, tClass);
    }

    /**
     * 对象源拷贝到目标对象
     *
     * @param source
     * @param target
     * @param <T>
     * @return
     */
    public static <T> List<T> listToList(final List<?> source, final Class<T> target) {
        Assert.notEmpty(source);
        Assert.notNull(target);
        List<T> newList = Lists.newArrayList();
        for (Object o : source) {
            try {
                T t = target.newInstance();
                copyProperties(o, t);
                newList.add(t);
            } catch (InstantiationException e) {
                log.error("listToList is error: ", e);
            } catch (IllegalAccessException e) {
                log.error("listToList is error: ", e);
            }
        }
        return newList;
    }

    /**
     * 根据源目标类型、目标类型，生产唯一的key
     *
     * @param source
     * @param target
     * @return
     */
    public static String generateKey(final Class source, final Class target) {
        Assert.notNull(source);
        Assert.notNull(target);
        StringBuilder stringBuilder = new StringBuilder(50);
        stringBuilder.append(source.toString()).append(target.toString());
        return stringBuilder.toString();
    }

    /**
     * 对象源拷贝到目标对象
     *
     * @param source
     * @param target
     * @param <T>
     * @return
     */
    public static <T> T objectToObject(final Object source, final Class<T> target) {
        Assert.notNull(source);
        Assert.notNull(target);
        T t = null;
        try {
            t = target.newInstance();
            copyProperties(source, t);
        } catch (InstantiationException e) {
            log.error("objectToObject is error: ", e);
        } catch (IllegalAccessException e) {
            log.error("objectToObject is error: ", e);
        }
        return t;
    }

    /**
     * 对象拷贝
     *
     * @param source
     * @param target
     */
    public static void copyProperties(final Object source, final Object target) {
        Assert.notNull(source);
        Assert.notNull(target);
        BeanCopier beanCopier = null;
        if (!beanCopierMap.containsKey(generateKey(source.getClass(), target.getClass()))) {
            beanCopier = BeanCopier.create(source.getClass(), target.getClass(), false);
            beanCopierMap.put(generateKey(source.getClass(), target.getClass()), beanCopier);
        } else {
            beanCopier = beanCopierMap.get(generateKey(source.getClass(), target.getClass()));
        }
        beanCopier.copy(source, target, null);
    }
}
